<?php
/**
 * Classe abstrata para ser herdada por todos os controladores de página obrigatóriamente
 * contém métodos para necessários para o funcionamento do framework assim como ferramentas de uso comum
 * para o usuário
 * 
 * @author cristiano
 */
abstract class Controle {
	protected $Sistema;
	protected $Aplicacao;
	protected $Core;
	protected $Dao;
	protected $TrocaConteudo = array();
	protected $Modelo;
	private   $NomeModelo = '';
	public    $titulo = "SofiaPHP::Framework Simples";
	protected $persistencia = false;
	protected $elementos_invisiveis = array();
	protected $input_values = array();
	private   $plugins = array();
	private   $onload = array();
	public    $master;

	/* Propriedades e métodos referentes ao datagrid */
	private $grid_campos = array();
	private $chave_primaria;
	private $acoes_permitidas = array();
	private $grid_filtros = array();
	private $grid_pagina;
	private $extensao_paginacao = 5;
	private $itens_por_pagina = 20;
	private $ordenacao = array();
	private $query = null;

	public function SetGridQuery(Doctrine_Query $query){
		$this->query = $query;
	}

	/**
	 * @return Doctrine_Query
	 */
	public function GetGridQuery(){
		return $this->query;
	}
	
	/**
	 * Retorna a página mestre (html mestre) do controlador
	 */
	public function GetMaster(){
		return $this->master;
	}

	/**
	 * Configura a página mestre (html mestre) do sistema, pode ser uma string para uma página só ou um array de páginas mestre
	 * a serem chamadas pelo renderizador na hora da inclusão dos html's
	 * @param mixed
	 */
	public function SetMaster($valor){
		$this->master = $valor;
	}

	/**
	 * Função responsável por registrar os campos que serão usados para o datagrid montar as informações de tela
	 * Caso não seja passado nenhum parâmetro ele retorna um array com os campos cadastrados.
	 *
	 * @param array
	 */
	public function GridCampos($campos = ''){
		if($campos != '' && sizeof($campos) > 0){
			foreach($campos as $key => $valor){
				$this->grid_campos[$key] = $valor;
			}
		}else{
			return $this->grid_campos;
		}
	}

	/**
	 * Esta função está relacioanda diretamente ao datagrid, nada mais é do que o nome do campo cujo seja a chave primária
	 * do modelo que será usado de base para criação do datagrid.
	 * 
	 * @param mixed
	 */
	public function ChavePrimaria($chave = ''){
		if($chave){
			$this->chave_primaria = $chave;
		}else{
			return $this->chave_primaria;
		}
	}

	/**
	 * Define para o sistema quais ações são permitidas pelo usuário no datagrid as funções disponiveis são editar e excluir passadas como array no seguinte formato:
	 * @param array $acoes
	 */
	public function GridSetAcoes($acoes){
		if(is_array($acoes)){
			foreach($acoes as $acao){
				array_push($this->acoes_permitidas, $acao);
			}
		}else{
			array_push($this->acoes_permitidas, $acoes);
		}
	}

	/**
	 * retorna array com as ações permitidas
	 */
	public function GridGetAcoes(){
		return $this->acoes_permitidas;
	}

	/**
	 * Filtros são os campos que devem ser filtrados da tabela na hora de gerar o sql para o datagrid, no formato:
	 * array('nome_do_campo' => 'valor_do_campo')
	 * o que representaria no "sql nome_do_campo = valor_do_campo"
	 * O sistema ainda não suporta simbolos de diferente maior ou menor, apenas igual
	 * @param array $filtros
	 */
	public function GridFiltros($filtros = ''){
		if($filtros != '' && sizeof($filtros) > 0){
			foreach($filtros as $key => $valor){
				$this->grid_filtros[$key] = $valor;
			}
		}else{
			return $this->grid_filtros;
		}
	}

	/**
	 * Número inteiro representante da paginação do datagrid ao configurar esta página com algum número (dentro da extensão da paginação)
	 * o usuário visualizará o datagrid na página configurada
	 * 
	 * @param integer $pagina
	 */
	public function GridPagina($pagina = ''){
		if($pagina){
			$this->grid_pagina = $pagina;
		}else{
			return $this->grid_pagina;
		}
	}
	
	/**
	 * Número inteiro que representa a extensão da barra de paginação, supondo que o usuário esteja na página 1 da paginação do datagrid
	 * e supondo também que a extensão exteja configurada para 5 então o usuário (a depender da quantidade de registros) visualizará além do 
	 * número 1 na barra de paginação outros números até o número 5
	 * 
	 * @param integer $quantidade
	 */
	public function GridExtensaoPaginacao($quantidade = ''){
		if($quantidade){
			$this->extensao_paginacao = $quantidade;
		}else{
			return $this->extensao_paginacao;
		}
	}

	/**
	 * Quantidade de registros será exibida pelo datagrid em cada página da paginação
	 * padrão é 20
	 * 
	 * @param integer $quantidade
	 */
	public function ItensPorPagina($quantidade = ''){
		if($quantidade){
			$this->itens_por_pagina = $quantidade;
		}else{
			return $this->itens_por_pagina;
		}
	}

	/**
	 * Ordenação dos campos em ASC do datagrid
	 * 
	 * @param array $ordem
	 */
	public function Ordenacao($ordem = ''){
		if($ordem){
			$this->ordenacao = $ordem;
		}else{
			return $this->ordenacao;
		}
	}

	/* Fim das propriedades e métodos referentes ao datagrid */

	/**
	 * Adiciona uma função javascript no onload da página,
	 * só funciona quando não há nenhuma class Mensagem configurada
	 * 
	 * Função javascript deve ser passada
	 * @param string $funcao
	 */
	public function AddOnLoad($funcao){
		$this->onload = $funcao;
	}

	/**
	 * retorna a função javascript registrada para ser iniciada no onload da página
	 * 
	 * @return string
	 */
	public function GetOnload(){
		return $this->onload;
	}

	/**
	 * retorna os plugins registrado no controlador
	 * 
	 * @return array
	 */
	public function GetPlugins(){
		return $this->plugins;	
	}

	/**
	 * Registra nome dos plugins que serão chamados pelo controlador
	 * @param array
	 */
	public function AddPlugins($plugins){
		foreach($plugins as $plugin){
			array_push($this->plugins, $plugin);
		}
	}

	/**
	 * Configura algum valor a um determinado campo do html que possui id e atributo value como input type text por exemplo
	 * @param string $id
	 * @param string $valor
	 */
	public function SetInputValor($id, $valor){
			$this->input_values[$id] = $valor;
	}
	
	/**
	 * Retorna os valores configurados pelo controlador para determinados campos de de formulários
	 * 
	 * @return array
	 */
	public function GetInputValores(){
		return $this->input_values;
	}
	
	/**
	 * Com base em um id passado esconde elementos usando método css display = none;
	 * 
	 * @param string $id
	 */
	public function EscondeElemento($id){ 
		array_push($this->elementos_invisiveis, $id);
	}

	/**
	 * Remove algum id da lista de elementos a serem escondidas via css
	 * @param string $id
	 */
	public function MostraElemento($id){
		$elements = $this->elementos_invisiveis;
		$tmp_array = array();
		
		for($i = 0; $i < sizeof($elements); $i++){
			if($id != $elements[$i]){
				array_push($tmp_array, $id);
			}
		}
		
		$this->elementos_invisiveis = $tmp_array;
	}
	
	/**
	 * Retorna a lista atual de elementos que serão escondidos
	 */
	public function GetElementosHidden(){
		return $this->elementos_invisiveis;
	}

	/**
	 * Retorna Sistema
	 * 
	 * @return Sistema
	 */
	public function GetSistema(){
		return $this->Sistema;
	}

	/**
	 * Retorna Aplicacao
	 * 
	 * @return Aplicacao
	 */
	Public function GetAplicacao(){
		return $this->Aplicacao;
	}

	/**
	 * Retorna Core
	 * 
	 * @return Core
	 */
	public function GetCore(){
		return $this->Core;
	}

	/**
	 * Retorna Dao
	 * 
	 * @return Dao
	 */
	public function GetDao(){
		return $this->Dao;
	}

	/**
	 * Retorna o nome do modelo configurado da classe
	 * 
	 * @return string
	 */
	public function NomeModelo($modelo = ''){
		if($modelo){
			$this->NomeModelo = $modelo;
		}else{
			return $this->NomeModelo;
		}
	}
	
	/**
	 * Retorna Instancia do Modelo
	 * 
	 * @return Modelo
	 */
	public function Modelo($modelo = ''){
		if(!empty($modelo)){
			$this->Modelo = $modelo;
		}else{
			return $this->Modelo;
		}
	}
	
	/**
	 * Este método retorna o título da tela
	 * 
	 * @deprecated
	 * @param $title
	 */
	public function Titulo($title  = ''){
		if($title){
			$this->titulo = $title;
		}else{
			return $this->titulo;
		}
	}

	/**
	 * Controla se os dados serão persistentes em tela ou não.
	 * 
	 * @param $per boolean
	 * @return boolean
	 */
	public function Persistencia($per = false){
		if($per != ''){
			$this->persistencia = $per;
		}else{
			return $this->persistencia;
		}
	}

	/**
	 * Realiza operações manuais na exibição dos dados na tela.
	 * Prescisa ser implementado no controlador da página
	 */
	public function MostraTela(){}

	/**
	 * Inicializa parametros necessários de acordo com o Controlador que está sendo usado, método para ser implementado
	 * no controlador.
	 *
	 * @return void
	 */
	public function Init(){}

	/**
	 * Inicia a conexão do doctrine com o banco de dados
	 */
	public function InitDB(){
		$this->Dao = Dao::GetInstancia();
		$this->Dao->Conectar();
	}

	/**
	 * Retorna a lista de tags com seus respectivos conteudos cadastrados até o momento
	 * 
	 * @return array
	 */
	public function GetTrocaConteudo(){
		return $this->TrocaConteudo;
	}

	/**
	 * Método construtor da classe, gera instancias de Sistema, Aplicação e Core
	 */
	function __construct() {
		$this->Sistema = Sistema::GetInstancia();
		$this->Aplicacao = Aplicacao::GetInstancia();
		$this->Core = Core::GetInstancia();
	}

	/**
	 * Salva o Modelo configurado ao controlador no banco de dados
	 */
	public function Salvar(){
	   $this->modelo = $this->GetDao()->salvar($this->Modelo());
	   Mensagens::NovaMensagem('Sucesso', 'Registro salvo com sucesso!');
	}

	/**
	 * Remove o registro do modelo vinculado ao controlador do banco de dados
	 */
	public function Excluir(){
		$this->Modelo()->delete();
		echo "Registro removido com sucesso!";
		die();
	}

	/**
	 * Faz com que os dados enviados por formulários sejam persistentes em tela
	 */
	public function Editar(){
		$this->Persistencia(true);
	}

	/**
	 * Muda o nome do campo tipo file enviado por formulário
	 * Esta ferramenta mudará de lugar na próxima versão
	 * 
	 * @param array $file
	 * @param string $prefixo
	 */
	protected function MudaNomeArquivo(array $file, $prefixo){
            $name = Utils::TimestampAtual();
            $ext = end(@explode('.', $file['name'] ));
            $file['name'] = ("$prefixo{$name}.{$ext}");
            return $file;
    }

	/**
	 * Configuração prévia do modelo usado pelo controle e também das propriedades de formulário
	 * do controle.
	 * 
	 * @return void
	 */
    public function ConfiguraModelo(){
    	$parans = $this->GetSistema()->GetParametros();
   		$pre = 'set_';

    	if($this->NomeModelo() != ''){
			$tmp_nome_modelo = $this->NomeModelo();

    		if(isset($parans['id']) && $parans['id'] != '' ){
    			$modelo = $this->GetDao()->busca_por_id($tmp_nome_modelo, $parans['id'] );
    		}else{
    			$modelo = new $tmp_nome_modelo;
    		}
    		
    		$sets = get_class_methods($modelo);
    		foreach($parans as $paran => $val){ // Configurando propriedades do modelo caso exista
    			for($i = 1; $i < sizeof($sets); $i++){
    				$param_set = $pre . $paran;
    				if($param_set == $sets[$i]){
    					$metodo = $sets[$i];
    					$modelo->$metodo($val);
    				}
    			}
    		}
    		$this->Modelo($modelo);
    	}

    	$sets = get_class_methods($this);

    	foreach($parans as $paran => $val){ // Configurando propriedades do controle
    		$size_sets = sizeof($sets);
    		for($i = 1; $i < $size_sets; $i++){
    			$param_set = $pre . $paran;
    			if($param_set == $sets[$i]){
    				$metodo = $sets[$i];
    				$this->$metodo($val);
    			}
    			if($i == sizeof($sets)){
    				break;
    			}
    		}
    	}

    }

    /**
     * Adicionaa tags a lista de tags para que o php troque as mesmas por seus respetivos conteúdos gerados pelo php
     * em tempo de renderização
     * 
     * @param $valores
     */
    public function AddTagConteudo($valores){
    	foreach($valores as $val => $content){
    		$this->TrocaConteudo[$val] = $content;
    	}
    }

    /**
     * Executa alguns procedimentos finais
     */
    public function Finaliza(){
    	$this->AddTagConteudo(array('titulo_pagina'=> $this->titulo));
    }

    /**
     * Converte algum Modelo em XML
     * Este método mudará de lugar na próxima versão
     * 
     * @param Doctrine_Collection
     */
	public function DoctrineToXml(Doctrine_Collection $dr){

		$xml = "<registros>";
		foreach($dr as $materia){
			$ar_mat = $materia->toArray(true);
			$xml .= "<item>";
			foreach($ar_mat as $chave => $valor){
				$xml .= "<$chave>$valor</$chave>";
			}
			$xml .= "</item>";
		}
		$xml .= "</registros>";

		return $xml;
	}

	/**
	 * Gera o datagrid da página com base em configurações pré definidas no controlador
	 * @param boolean
	 */
	public function GeraDataGrid($interna = false){
		if(!$this->GetDao()){
			$this->InitDB();
		}
		
		$dg = new DataGrid();
		$dg->AjustaControle($this);
		$dt_grid = $dg->GerarDataGrid();
		
		if($interna){
			return $dt_grid;
		}

		die($dt_grid);
	}
	
}